package yl.hs.bmipfull.viewmodels;

import yl.hs.bmipfull.annotations.DBField;
import yl.hs.bmipfull.utils.Tl;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;

/**
 * @author 谢景广
 * @category 视图模型基类
 */
public class BaseModel {
    /**
     * 将当前对象所有值拷贝到指定的对象中
     *
     * @param object 目标实例
     * @throws Exception 异常
     */
    public void copyTo(Object object) throws Exception {
        var methods = this.getClass().getMethods();
        var tmths = object.getClass().getMethods();
        for (var m : methods) {
            var mname = m.getName();
            if (mname.startsWith("get") || mname.startsWith("is")) {
                var mfield = "";
                if (mname.startsWith("get")) {
                    mfield = mname.substring(3);
                }
                if (mname.startsWith("is")) {
                    mfield = mname.substring(2);
                }
                Method setmth = null;
                for (var tm : tmths) {
                    if (tm.getName().equals("set" + mfield)) {
                        setmth = tm;
                        break;
                    }
                }
                if (setmth != null) {
                    setmth.invoke(object);
                }
            }
        }
    }

    public void loadForEntity(Object object) throws Exception {
        var methods = object.getClass().getMethods();
        var tmths = this.getClass().getMethods();
        for (var m : methods) {
            var methodName = m.getName();
            if (methodName.startsWith("get") || methodName.startsWith("is")) {
                var fieldName = "";
                if (methodName.startsWith("get")) {
                    fieldName = methodName.substring(3);
                }
                if (methodName.startsWith("is")) {
                    fieldName = methodName.substring(2);
                }
                Method setmth = null;
                for (var tm : tmths) {
                    if (tm.getName().equals("set" + fieldName)) {
                        setmth = tm;
                        break;
                    }
                }
                if (setmth != null) {
                    setmth.invoke(this);
                }
            }
        }
    }

    /***
     * 获取视图模型和实体之间的差异明细
     * @param object 要对比的实体
     * @return 变更日志内容
     * @throws Exception 异常
     */
    public String genChangeLog(Object object) throws Exception {
        var methods = this.getClass().getMethods();
        var targetMethods = object.getClass().getMethods();
        var logList = new ArrayList<String>();
        for (var m : methods) {
            var methodName = m.getName();
            var fieldName = "";

            if (methodName.startsWith("get")) {
                fieldName = methodName.substring(3);
            }
            if (methodName.startsWith("is")) {
                fieldName = methodName.substring(2);
            }
            var fields = this.getClass().getDeclaredFields();
            Field field = Tl.getField(fields, fieldName);
            if (field != null && field.isAnnotationPresent(DBField.class)) {
                DBField log = field.getAnnotation(DBField.class);
                var value = m.invoke(this);
                Object oldValue = null;
                for (var tm : targetMethods) {
                    if (tm.getName().equals(methodName)) {
                        oldValue = tm.invoke(object);
                        break;
                    }
                }
                var valueStr = "";
                var oldValueStr = "";
                if (field.getType().equals(Date.class)) {
                    var format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                    if (value != null) {
                        valueStr = format.format(value);
                    }
                    if (oldValue != null) {
                        oldValueStr = format.format(oldValue);
                    }
                } else {
                    if (value != null) {
                        valueStr = value.toString();
                    }
                    if (oldValue != null) {
                        oldValueStr = oldValue.toString();
                    }
                }
                if (!valueStr.equals(oldValueStr)) {
                    logList.add(String.format("%s[%s→%s]", log == null ? methodName : log.disName(),
                            oldValue, valueStr
                    ));
                }
            }
        }
        if (logList.size() > 0) {
            var array = new String[logList.size()];
            return String.join(",", logList.toArray(array));
        }
        return "";
    }
}
